package com.yunhe.authority.service.authority.impl;

import com.alibaba.fastjson.JSON;
import com.yunhe.authority.domain.authority.Organization;
import com.yunhe.authority.domain.authority.User;
import com.yunhe.authority.repository.authority.OrganizationRepository;
import com.yunhe.authority.service.authority.OrganizationService;
import com.yunhe.authority.util.MyHeaderUtil;
import com.yunhe.common.filter.ServerContextHolder;
import com.yunhe.common.util.RedisClient;
import org.springframework.beans.factory.annotation.Autowired;
import com.yunhe.common.exception.ArgumentErrorException;
import com.yunhe.common.exception.ObjectNotFoundException;
import com.yunhe.common.exception.UniqueConstraintsException;
import com.yunhe.common.model.PageParam;
import com.yunhe.common.util.StringUtil;
import com.yunhe.common.util.CollectionUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author zhengbo
 * @date 2021/2/24 10:19
 */
@Service
public class OrganizationServiceImpl implements OrganizationService {

    @Autowired
    private OrganizationRepository organizationRepository;

    @Autowired
    private MyHeaderUtil headerUtil;

    @Autowired
    private RedisClient redisClient;

    @Override
    public Iterable<Organization> findByUserId(Long userId, Long stationId, Long firmId) {
        if(stationId != null){
            return organizationRepository.findByUserIdAndStationId(userId,stationId);
        }else if(firmId != null){
            return organizationRepository.findByUserIdAndFirmId(userId,firmId);
        }
        return null;
    }

    @Override
    public Iterable<Organization> findBelongOrgByUserId(Long userId, Long stationId, Long firmId) {
        if(stationId != null){
            return organizationRepository.findBelongOrgByUserIdAndStationId(userId,stationId);
        }else if(firmId != null){
            return organizationRepository.findBelongOrgByUserIdAndFirmId(userId,firmId);
        }
        return null;
    }

    /**
     * 组织对象处理和判断
     * @param item 组织对象
     */
    private void processBeforeSave(Organization item)
            throws ArgumentErrorException, UniqueConstraintsException {
        //判断组织编号、组织标题是否为空
        if ( StringUtil.isEmpty(item.getTitle())) {
            throw new ArgumentErrorException("组织编号、组织标题不能为空");
        }
//        //判断组织名是否已存在
//        Organization organizationByName = organizationRepository.findByName(item.getName());
//        if (organizationByName != null) {
//            if (item.getId() == null || organizationByName.getId().longValue() != item.getId().longValue()) {
//                throw new UniqueConstraintsException("该菜单名已存在");
//            }
//        }
    }



    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    public Organization createOrganization(Long firmId, Long stationId, Long parentId, Organization organization)
            throws UniqueConstraintsException, ArgumentErrorException, ObjectNotFoundException {
        organization.setId(null);
        processBeforeSave(organization);

        if (stationId != null) {
            Organization existTitleOrganization = organizationRepository.findOrganizationByStationIdAndTitle(stationId, organization.getTitle());
            if (existTitleOrganization != null) {
                throw new UniqueConstraintsException(organization.getTitle() + "已存在");
            }
        }

        if (parentId != null) {
            //设置level
            Optional<Organization> parentOrganization = organizationRepository.findById(parentId);
            parentOrganization.ifPresent(item -> organization.setLevel(item.getLevel()+1));
        } else {
            //父级level为1
            organization.setLevel(1);
        }

        organization.setCreateTime(System.currentTimeMillis());
        Organization newOrganization = organizationRepository.save(organization);

        //绑定父单位关系
        updateParent(newOrganization.getId(), parentId);
        return newOrganization;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    public void deleteOrganization(List<Long> ids) {
        for (Long id : ids) {
            List<Organization> organizationChildren = (List<Organization>)organizationRepository.findChildren(id);
            List<Long> childrenIdsIds = searchChildrenIds(organizationChildren, ids);
            deleteByIds(childrenIdsIds);
        }
        deleteByIds(ids);
    }

    private List<Long> searchChildrenIds(List<Organization> organizationChildren, List<Long> ids) {
        List<Long> newIds = new ArrayList<>(ids);
        if (CollectionUtil.isNotEmpty(organizationChildren)) {
            organizationChildren.forEach(item -> {
                newIds.add(item.getId());
                List<Organization> newOrganizationChildren = (List<Organization>) organizationRepository.findChildren(item.getId());
                if (CollectionUtil.isNotEmpty(newOrganizationChildren)) {
                    this.searchChildrenIds(newOrganizationChildren, newIds);
                }
            });
        }
        return newIds;
    }

    private void deleteByIds(List<Long> ids) {
        if (CollectionUtil.isNotEmpty(ids)) {
            for (Long id : ids) {
                organizationRepository.deleteById(id);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    public Organization updateOrganization(Long parentId, Organization organization)
            throws UniqueConstraintsException, ArgumentErrorException, ObjectNotFoundException {
        processBeforeSave(organization);

        Optional<Organization> oldOrganization = organizationRepository.findById(organization.getId());
        if (!oldOrganization.isPresent()) {
            throw new ObjectNotFoundException("找不到ID为" + organization.getId() + "的组织");
        }

        Organization newOrganization = organizationRepository.save(organization);
        //绑定父菜单关系
        updateParent(organization.getId(), parentId);

        String orgName = redisClient.get("OrgName:" + organization.getId());
        if (!StringUtil.isEmpty(orgName)){
            redisClient.set("OrgName:" + organization.getId(), JSON.toJSONString(organization));
        }
        return newOrganization;
    }

    @Override
    public Organization searchById(Long id) {
        Organization organization = null;
        Optional<Organization> organizationOptional = organizationRepository.findById(id);
        //判断组织是否存在
        if (organizationOptional.isPresent()) {
            organization = organizationOptional.get();
            //查询子组织
            List<Organization> organizationChildren = (List<Organization>)organizationRepository.findChildren(id);
            if(CollectionUtil.isNotEmpty(organizationChildren)) {
                organization.setChildren(organizationChildren);
                //查询子组织下的子组织
                searchChild(organizationChildren);
            }
        }

        return organization;
    }

    @Override
    public Page<Organization> searchByCondition(String name, String title, PageParam pageParam) {
        Pageable pageable = PageRequest.of(pageParam.getPage(),pageParam.getSize());
        Page<Organization> organizationPage = organizationRepository.findAll(pageable);
        List<Organization> organizationList = organizationPage.getContent();
        searchChild(organizationList);
        organizationPage = new PageImpl<>(organizationList);
        return organizationPage;
    }

    private void searchChild(List<Organization> organizationList) {
        if (CollectionUtil.isNotEmpty(organizationList)) {
            //查询子集
            organizationList.forEach(organization -> {
                List<Organization> organizationListChild = (List<Organization>) organizationRepository.findChildren(organization.getId());
                if (CollectionUtil.isNotEmpty(organizationListChild)) {
                    organization.setChildren(organizationListChild);
                    //继续查询子集
                    searchChild(organizationListChild);
                }
            });
        }
    }


    @Override
    public List<Organization> searchByStationId(Long stationId) {
        List<Organization> organizationList = (List<Organization>)organizationRepository.findOrganizationByStationId(stationId);
        searchChild(organizationList);
        return organizationList;
    }

    @Override
    public List<Organization> searchByStationIdOrFirmId(Long stationId, Long firmId) {
        List<Organization> organizationList = new ArrayList<>();
        if (stationId != null) {
            organizationList = (List<Organization>)organizationRepository.findOrgByStationId(stationId);
        }
        if (firmId != null) {
            organizationList = (List<Organization>)organizationRepository.findOrgByFirmId(firmId);
        }

        organizationList = organizationList.stream().filter(organization -> 1 == organization.getLevel()).collect(Collectors.toCollection(ArrayList::new));
        searchChild(organizationList);
        return organizationList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    public void organizationBindAndUnbind(Long stationId, Long firmId, Long id) throws ArgumentErrorException {
        if (id == null) {
            throw new ArgumentErrorException("请选择组织！");
        }
        if (stationId == null && firmId == null) {
            throw new ArgumentErrorException("参数有误，请确认绑定的主体！");
        }

        //绑定项目
        if (stationId != null) {
//            //先解绑再绑定
//            organizationRepository.organizationUnbindByStation(stationId);
            organizationRepository.organizationBindStation(id, stationId);
        }
        //绑定单位
        if (firmId != null) {
//            //先解绑再绑定
//            organizationRepository.organizationUnbindFirm(firmId);
            organizationRepository.organizationBindFirm(id, firmId);
        }
    }

    @Override
    public Iterable<Organization> getOrgByLoginUser(Long firmId, Long stationId, String orgFunction, Boolean childFlag, String orgType) throws ArgumentErrorException {
        User headerUser = headerUtil.getHeaderUser();
        if(headerUser == null){
            throw new ArgumentErrorException("该用户登录信息已过期，请重新登录");
        }
        if(firmId == null && stationId != null){
            if(childFlag){
                if("belong".equals(orgType)){
                    return findBelongChildOrgByUserId(headerUser.getId(),stationId,orgFunction,null);
                }else if("synergy".equals(orgType)){
                    return findSynergyChildOrgByUserId(headerUser.getId(),stationId,orgFunction,null);
                }
            }else {
                if("belong".equals(orgType)){
                    return findBelongOrgByUserId(headerUser.getId(),stationId,orgFunction,null);
                }else if("synergy".equals(orgType)){
                    return findSynergyOrgByUserId(headerUser.getId(),stationId,orgFunction,null);
                }

            }
        }else if(stationId == null && firmId != null){
            //todo 目前没有单位账号 先不做逻辑处理
        }
        return null;
    }

    @Override
    public Iterable<Organization> getSubOrg(String orgIdStr) {
        String[] split = orgIdStr.split("-");
        if("station".equals(split[1])){
            return organizationRepository.findSubOrgByOrgId(Long.parseLong(split[0]));
        }else if("firm".equals(split[1])){
            //todo 目前没有单位账号 先不做逻辑处理
        }
        return null;
    }

    @Override
    public List<Organization> searchOrgByStationId(Long stationId) {
        return (List<Organization>) organizationRepository.findOrgByStationId(stationId);
    }

    @Override
    public List<Organization> findChildOrg(Long orgId, Long stationId) {
        return (List<Organization>) organizationRepository.findChildOrg(orgId,stationId);
    }

    @Override
    public List<Organization> searchOrgByOrgFunction(String orgFunction) throws ArgumentErrorException {
        String projectCode = ServerContextHolder.getContext().getProjectCode();
        if(StringUtil.isEmpty(projectCode)){
            throw new ArgumentErrorException("请选择对应项目进行操作");
        }
        return organizationRepository.findOrgByStationIdAndorgFunction(orgFunction,Long.valueOf(projectCode));
    }

    @Override
    public Iterable<Organization> findSynergyOrgByUserId(Long userId, Long stationId, Long firmId) {
        if(stationId != null){
            return organizationRepository.findSynergyOrgByUserIdAndStationId(userId,stationId);
        }else if(firmId != null){
            //return organizationRepository.findA(userId,firmId);
        }
        return null;
    }

    @Override
    public List<Organization> getAllOrgByLoginUser(Boolean childFlag) throws ArgumentErrorException {
        List<Organization> organizations = new ArrayList<>();
        Long headerUserId = headerUtil.getHeaderUserId();
        if(headerUserId == null){
            throw new ArgumentErrorException("该用户登录信息已过期，请重新登录");
        }
        String projectCode = ServerContextHolder.getContext().getProjectCode();
        if(StringUtil.isEmpty(projectCode)){
            throw new ArgumentErrorException("请选择项目进行操作！");
        }
        subOrgByUserIdAndStationId(childFlag, organizations, headerUserId, Long.valueOf(projectCode));
        return organizations;
    }

    private void subOrgByUserIdAndStationId(Boolean childFlag, List<Organization> organizations, Long headerUserId, Long stationId) {
        Iterable<Organization> belongOrgByUserId = findBelongOrgByUserId(headerUserId, stationId, null);
        if (belongOrgByUserId != null) {
            for (Organization organization : belongOrgByUserId) {
                organizations.add(organization);
            }
        }
        Iterable<Organization> synergyOrgByUserId = findSynergyOrgByUserId(headerUserId, stationId, null);
        if (synergyOrgByUserId != null) {
            for (Organization organization : synergyOrgByUserId) {
                organizations.add(organization);
            }
        }
        if (childFlag) {
            Iterable<Organization> belongChildOrgByUserId = findBelongChildOrgByUserId(headerUserId, stationId, null);
            if (belongChildOrgByUserId != null) {
                for (Organization organization : belongChildOrgByUserId) {
                    organizations.add(organization);
                }
            }
            Iterable<Organization> synergyChildOrgByUserId = findSynergyChildOrgByUserId(headerUserId, stationId, null);
            if (synergyChildOrgByUserId != null) {
                for (Organization organization : synergyChildOrgByUserId) {
                    organizations.add(organization);
                }
            }
        }
    }


    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object,Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    @Override
    public List<Organization> getSubOrgByLoginUser(Long stationId, Long userId, Boolean childFlag) {
        List<Organization> organizations = new ArrayList<>();
        subOrgByUserIdAndStationId(childFlag, organizations, userId, stationId);
        if(CollectionUtil.isNotEmpty(organizations)){
            return organizations.stream().filter(distinctByKey(b -> b.getId())).collect(Collectors.toList());
        }
        return organizations;
    }

    private Iterable<Organization> findSynergyChildOrgByUserId(Long id, Long stationId, Long firmId) {
        if(firmId == null && stationId != null){
            Iterable<Organization> iterable = organizationRepository.findSynergyChildOrgByUserId(id, stationId);
            return iterable;
        }else if(stationId == null && firmId != null){
            //todo 目前没有单位账号 先不做逻辑处理
        }
        return null;
    }

    private Iterable<Organization> findBelongChildOrgByUserId(Long id, Long stationId, Long firmId) {
        if(firmId == null && stationId != null){
            Iterable<Organization> iterable = organizationRepository.findBelongChildOrgByUserId(id, stationId);
            return iterable;
        }else if(stationId == null && firmId != null){
            //todo 目前没有单位账号 先不做逻辑处理
        }
        return null;
    }

    private Iterable<Organization> findSynergyOrgByUserId(Long id, Long stationId, String orgFunction, Long firmId) {
        if(firmId == null && stationId != null){
            return organizationRepository.findSynergyOrgByUserIdAndStationId(id,stationId,orgFunction);
        }else if(stationId == null && firmId != null){
            //todo 目前没有单位账号 先不做逻辑处理
        }
        return null;
    }

    private Iterable<Organization> findSynergyChildOrgByUserId(Long id, Long stationId, String orgFunction, Long firmId) {
        if(firmId == null && stationId != null){
            //过滤当前人所在的部门
            //Iterable<Organization> organizations = organizationRepository.findSynergyOrgByUserIdAndStationId(id, stationId, orgFunction);
            Iterable<Organization> iterable = organizationRepository.findSynergyChildOrgByUserId(id, stationId, orgFunction);
//            if(iterable != null){
//                while (iterable.iterator().hasNext()){
//                    Organization childOrg = iterable.iterator().next();
//                    if(organizations != null){
//                        if(organizations.iterator().hasNext()){
//                            Organization organization = organizations.iterator().next();
//                            if(childOrg.getId().longValue() == organization.getId().longValue()){
//                                iterable.iterator().remove();
//                            }
//                        }
//                    }
//
//                }
//            }
            return iterable;
        }else if(stationId == null && firmId != null){
            //todo 目前没有单位账号 先不做逻辑处理
        }
        return null;
    }

    private Iterable<Organization> findBelongChildOrgByUserId(Long id, Long stationId, String orgFunction, Long firmId) {
        if(firmId == null && stationId != null){
            //过滤当前人所在的部门
            //Iterable<Organization> organizations = organizationRepository.findBelongOrgByUserIdAndStationId(id, stationId, orgFunction);
            Iterable<Organization> iterable = organizationRepository.findBelongChildOrgByUserId(id, stationId, orgFunction);
//            if(iterable != null){
//                while (iterable.iterator().hasNext()){
//                    Organization childOrg = iterable.iterator().next();
//                    if(organizations != null){
//                        if(organizations.iterator().hasNext()){
//                            Organization organization = organizations.iterator().next();
//                            if(childOrg.getId().longValue() == organization.getId().longValue()){
//                                iterable.iterator().remove();
//                            }
//                        }
//                    }
//
//                }
//            }
            return iterable;
        }else if(stationId == null && firmId != null){
            //todo 目前没有单位账号 先不做逻辑处理
        }
        return null;
    }

    private Iterable<Organization> findBelongOrgByUserId(Long id, Long stationId, String orgFunction, Long firmId) {
        if(firmId == null && stationId != null){
            return organizationRepository.findBelongOrgByUserIdAndStationId(id,stationId,orgFunction);
        }else if(stationId == null && firmId != null){
            //todo 目前没有单位账号 先不做逻辑处理
        }
        return null;
    }


    /**
     * 更新父组织关系（添加到父组织）
     * @param childId 子组织对象
     * @param parentId 父组织ID
     */
    private void updateParent(Long childId, Long parentId) throws ObjectNotFoundException {
        Organization organization = this.searchById(childId);
        if (organization == null) {
            throw new ObjectNotFoundException("找不到ID为" + childId + "的组织");
        }
        //更新父菜单关系
        updateParentRelation(childId, parentId);
    }

    /**
     * 更新父菜单关系
     * @param childId 子菜单ID
     * @param parentId 父菜单ID
     */
    private void updateParentRelation(Long childId, Long parentId) throws ObjectNotFoundException {
        if (parentId != null) {
            Organization organizationMenu = this.searchById(parentId);
            if (organizationMenu == null) {
                throw new ObjectNotFoundException("找不到ID为" + parentId + "的父组织");
            }
            //先删除原父子关系
            organizationRepository.delChildRelation(childId);
            //再添加新父子关系
            organizationRepository.addChildRelation(parentId, childId);
        } else {
            organizationRepository.delChildRelation(childId);
        }
    }
}
